第 N 章 / StoryCam Session

部署上线、监控接线与发布治理

这一章记录 StoryCam 从“准备上线”到“生产基础设施打通”的过程:先用方案澄清边界,再补齐 P0 生产能力,最后落到 dev → main → release、Render、Supabase、Cloudflare、Sentry 和 uptime 的上线链路。

TL;DR

本 session 的主线是上线。

用户从“看看还缺什么”开始,逐步把 StoryCam 的部署边界、生产能力、发布流程和运维监控都推到可执行层面。

最核心的产品约束是异步生成。

用户明确要求关掉页面后继续生成并保存,生产必须是真实 final MP4,这直接推动了 worker-owned jobs 和 async final_work 的设计。

架构选择是同源全栈。

首版没有拆成 Vercel 前端 + Render 后端,而是 Render Web + Worker 承担 Next.js UI、API、后台任务和 ffmpeg final MP4。

发布纪律被用户拉直。

用户明确要求 push 后先 PR 到 dev,再从 dev PR 到 main,不能跳过 dev;Render 随 main 自动部署,release/tag 跟 main 对齐。

生产接线已经基本完成。

Render、Supabase、Google OAuth、Cloudflare、自定义域名、Sentry 独立项目、issue alerts、GitHub uptime/deep health 都被推进并验证。

剩余风险集中在真实验收。

还需要跑低成本真实 provider smoke、验证 ffmpeg 生产稳定性、决定是否补 staging、补 Render 告警并更新文档状态。

本章学习目标

学会把上线需求转成生产约束。

不要只问“部署到哪里”,要问用户是否会关页、是否需要真实产物、是否要跨地区访问、是否能接受直接生产 beta。

学会区分 P0 与 P1。

先保证可部署、可恢复、可观测、可控成本,再把 analytics、admin、自动 canary 和成本 dashboard 放进后续。

学会发布流程的门禁思维。

CI、PR review、dev → main、release/tag、自动部署和 uptime 不是形式,是生产系统的一部分。

学会用症状反推配置问题。

OAuth 跳 localhost 的截图不是“偶发 UI 问题”,而是 Google / Supabase / app URL 配置链路不一致的证据。

工具、参考图和可视化证据

开发与发布工具

GitHub PR / Actions、Render CLI/API、Supabase CLI、Google Cloud CLI、Cloudflare Wrangler 与 Dashboard、Sentry。

被点名或使用的技能

code-simplifiergstack-ship、GitHub code review / CI 修复流程、部署与上线检查思路。

项目内参考文件

docs/DEPLOYMENT.mddocs/OBSERVABILITY.mdrender.yamlscripts/storycam-worker.tsscripts/storycam-verify-live.mjs

关键截图证据:OAuth 回调落到 localhost

聊天中出现一张浏览器截图:地址栏显示 https://localhost:10000,页面返回 {"info":"Invalid request!"},用户说明“退出账号后重新总会先出现截图的问题,退回来显示登录成功了”。这张图的意义不是展示 UI,而是证明生产登录链路中存在 canonical URL / redirect URL 配置漂移。

不安全 https://localhost:10000
{"info":"Invalid request!"}

此处为文字化复刻,不嵌入原截图;没有臆造截图之外的信息。

沿时间排列的原始 Prompt

阶段 1:先出部署方案,不改代码
“这个项目准备上线部署了,看看还缺什么没有构建的,然后部署方案什么样更合适,有什么想进一步了解的可以问我,先出方案,不要改动代码。”
“首批用户还是国际化,大陆和海外都可以访问,我会用 cloudflare 的域名……需要用户关掉页面也继续生成并保存……生产必须真实 final MP4 artifact。”
教师批注:这是一个高质量上线 prompt。它没有直接要求“部署一下”,而是先让 agent 做缺口分析,并补充跨地区访问、关页继续生成、真实 MP4 等关键约束。读者可以学到:上线问题要先声明验收标准,而不是先选平台。
阶段 2:架构选择与 P0/P1 切分
“auth 先只有 google 可以,不用加……render 承担前后端的全栈部署,前端请求是不是 jwt 方式更安全,现在是不是 supabase 直接也是后端了?现在加监控的话,用 sentry?还是其他?后台管理视图什么方案?”
“render 有亚洲的节点么,supabase 是新加坡。PostHog 还是 Umami 更合适呢?”
教师批注:这组 prompt 把“部署平台”扩展到认证、安全、监控、后台、分析和区域延迟。它体现了产品负责人式的提问:不是问某个技术点,而是问一组上线后的运营问题。
阶段 3:沉淀文档与实施 P0
“好的,你先整个部署的文档在 docs 里,便于后面开发。”
“根据这个部署方案,根据项目最新的版本,给出进一步为了部署的开发计划。”
“PLEASE IMPLEMENT THIS PLAN: # StoryCam 部署前 P0 开发计划……”
教师批注:这里先让方案进入 docs,再让计划基于最新代码生成,最后才授权实施。读者可以学到一个可复用节奏:方案文档化 → 与代码对齐 → 生成计划 → 实施。
阶段 4:部署配置、环境变量与 OAuth 修复
“Supabase 可以使用 cli 完成,注意和 dev 项目不要冲突。Render 是不是用 cli 也可以?”
“配置 env 时,要看下现在本地的是不是完整。”
“The OAuth client was not found. 错误 401: invalid_client。你需要使用 google cloud cli 去配置。”
“但我退出账号后重新总会先出现截图的问题,退回来显示登录成功了,还是需要修复下。”
教师批注:用户持续把“能跑”推进到“体验上不能出现错误页面”。OAuth 这类配置 bug 的关键不是改代码,而是完整追踪 Google、Supabase、Render、Cloudflare 的 URL 链路。
阶段 5:发布纪律、监控与剩余上线清单
“现在部署环节,应该走流程 dev 到 main,同时要有 release 管理,然后 render 随着 main 更新自动更新。”
“你的流程应该是 push,然后 pr 到 dev,然后在 dev pr 到 main,不要跳。”
“Sentry 是不是还要配置上 issues 监控……storycam 不要在 geo-app/里,需要新建一个项目。”
“Cloudflare Cache/WAF/rate-limit 规则没有落地……自己打开 Chrome 操作即可。”
“还有哪些部署相关的计划没有完成?”
教师批注:这是从“单次部署”转向“发布系统”的关键阶段。用户不只要求功能完成,还要求分支纪律、监控归属、边缘规则、剩余风险清单,体现了生产化复盘能力。

时间线

01
用户原话“先出方案,不要改动代码。”
Codex 总结先盘点部署缺口:生产启动脚本、worker、provider readiness、final MP4、健康检查、监控和安全边界。
结果 / 影响:本 session 先以方案为中心,避免在未确认部署边界前直接改代码。
02
用户原话“大陆和海外都可以访问……Cloudflare 的域名……关掉页面也继续生成并保存……生产必须真实 final MP4 artifact。”
Codex 总结把部署问题转成生产系统约束:Cloudflare 入口、后台持久任务、真实媒体产物、Supabase 私有存储。
结果 / 影响:“浏览器不能是进度来源”成为架构转折点。
03
用户原话“Render 承担前后端的全栈部署……Supabase 直接也是后端了?”
Codex 总结明确 Supabase 是托管后端平台的一部分,但 StoryCam 服务端仍负责 workflow、provider、jobs、final MP4、quota 和权限。
结果 / 影响:保留 Render 同源全栈,避免前后端拆分带来的认证和跨域复杂度。
04
用户原话“Render 有亚洲的节点么,Supabase 是新加坡。PostHog 还是 Umami 更合适呢?”
Codex 总结选择 Render Singapore 对齐 Supabase Singapore。PostHog 更适合产品 funnel 和 workflow,Umami 更适合轻量访问分析。
结果 / 影响:区域和分析方案被拆分:Singapore 是 P0,PostHog 是 P1。
05
用户原话“先整个部署的文档在 docs 里。”
Codex 总结沉淀部署文档,覆盖 topology、env、Cloudflare、Sentry、P0/P1、release flow 和 open decisions。
结果 / 影响:口头方案变成后续开发的项目级 source of truth。
06
用户原话“根据这个部署方案,根据项目最新的版本,给出进一步为了部署的开发计划。”
Codex 总结形成 P0:Render scripts/Blueprint、provider 分项配置、real mode 强校验、Supabase claim RPC、worker locking、async final_work、Origin guard、quota、health、Sentry。
结果 / 影响:上线任务从“部署平台配置”变成“补齐生产能力”。
07
用户原话“PLEASE IMPLEMENT THIS PLAN……”
Codex 总结开始实施 P0。关键方向是 durable worker、job locking、只读 polling、真实 final MP4、同源防护和脱敏监控。
结果 / 影响:StoryCam 向 beta 生产门槛迈进,而不是只完成本地 demo。
08
用户原话“Supabase 可以使用 cli 完成,注意和 dev 项目不要冲突。”
Codex 总结用 CLI/平台工具推进配置,但强调 dev/prod 隔离,避免 migration、auth、storage 或 secret 指向错误项目。
结果 / 影响:部署工作进入真实平台配置阶段。
09
用户原话“一定需要 staging 预发布状态么,还是直接生产环境呢?”
Codex 总结建议 staging 更稳,但早期 beta 可接受 direct production,只要有 health、canary、rollback 和监控。
结果 / 影响:实际采用 dev → main → production beta,staging 完整环境成为待确认项。
10
用户原话“应该走流程 dev 到 main,同时要有 release 管理,然后 render 随着 main 更新自动更新。”
Codex 总结建立发布纪律:feature → dev → main → Render 自动部署 → release/tag 对齐。
结果 / 影响:发布流程本身成为 StoryCam 的生产资产。
11
用户原话“你的流程应该是 push,然后 pr 到 dev,然后在 dev pr 到 main,不要跳……ci 没通过。”
Codex 总结按用户纠正后的流程修复 CI 和 code review 建议,再继续合并。
结果 / 影响:CI/review 变成发布门禁,而不是发布后的补救。
12
用户原话“The OAuth client was not found……invalid_client。”
Codex 总结把问题定位到 Google OAuth client、Supabase Auth redirect、Render app URL 的配置链路。
结果 / 影响:登录链路被纳入生产验收,而不是只看页面可访问。
13
用户原话“storycam.znbuild.com,可以用这个二级域名。”
Codex 总结接入 Cloudflare 域名,配置 DNS、代理、缓存、动态绕过、WAF 和生成相关端点限流。
结果 / 影响:生产入口从 Render 默认域名迁移到 Cloudflare 管理域名。
14
用户原话“退出账号后重新总会先出现截图的问题,退回来显示登录成功了。”
Codex 总结截图显示 callback 先落到 localhost 并返回 Invalid request,说明 canonical redirect 仍有漂移。
结果 / 影响:修复目标从“最终能登录”提升到“登录过程中不能出现错误页面”。
15
用户原话“Sentry 是不是还要配置上 issues 监控……storycam 不要在 geo-app/里,需要新建一个项目。”
Codex 总结创建独立 StoryCam Sentry 组织/项目,配置 issue alerts,并保证事件上下文脱敏。
结果 / 影响:监控归属和告警规则更适合 StoryCam 自己的生产问题。
16
用户原话“Cloudflare Cache/WAF/rate-limit 规则没有落地……自己打开 Chrome 操作即可。”
Codex 总结在 CLI 权限不足时改用 Chrome / Dashboard 完成授权与规则配置;验证静态资源 cache HIT。
结果 / 影响:Cloudflare 从 DNS 接入补齐到缓存和基础防护。
17
用户原话“还有哪些部署相关的计划没有完成?”
Codex 总结复核剩余项:真实生产 smoke、ffmpeg 稳定性、staging、release/tag、Render 告警、文档收尾。
结果 / 影响:部署工作进入上线前验收清单阶段。

关键时刻

架构决策

Render 全栈优先

当时的问题
是否需要 Vercel 承担前端,Render 只承担当后端。
为什么重要
StoryCam 的 UI、API、auth callback、session、jobs、download route 在一个同源边界里更安全、更简单。
最终处理
首版使用 Render Web + Worker;Vercel 暂不进入核心应用部署。
生产门槛

关页后继续生成

当时的问题
如果 generation job 依赖浏览器 polling 推进,用户关页会中断体验。
为什么重要
AI 视频生成是长耗时任务,用户天然会离开页面。
最终处理
引入 worker-owned jobs、锁、run_after、claim RPC,让浏览器只观察状态。
故障根因

OAuth 的 localhost 漂移

当时的问题
用户退出重登会先看到 localhost invalid request,再返回成功。
为什么重要
这暴露出生产 canonical URL 和 OAuth redirect 配置未完全一致。
最终处理
沿 Google Cloud、Supabase、Render、Cloudflare 链路修复,并加入 uptime 检查。
运维判断

Cloudflare 不是成本控制的全部

当时的问题
Cloudflare rate-limit 权限和 plan 有限制,只能做短周期 burst 防护。
为什么重要
AI provider 成本来自登录用户动作,不能只靠 IP 层规则。
最终处理
Cloudflare 做边缘防护,服务端 per-user quota 才是主要成本控制。

关键决策表

方案 当时看起来的好处 为什么放弃或保留 最终选择
Vercel 前端 + Render 后端 常见 Next.js 部署组合,前端 CDN 体验好。 会增加跨域 cookie、CORS、OAuth redirect、CSRF、media URL 复杂度;对 durable generation 没有帮助。 放弃首版拆分;保留未来营销站可能性。
Render Web + Worker 全栈 同源边界清晰,Web/API/Auth/Worker/ffmpeg 在同一生产平台。 更符合 StoryCam 的 MVP 复杂度;需要验证 Native Runtime ffmpeg。 采用。
浏览器 polling 推进任务 实现简单,适合本地 demo。 用户关页会影响任务进度,不符合生产体验。 放弃作为进度来源;保留只读状态观察。
后台 worker claim jobs 任务可在用户离开后继续,支持锁、重试、延迟轮询。 需要 DB 字段、RPC、worker lifecycle 和 terminal state 防护。 采用为 P0。
直接生产 beta 更快开始真实验证,减少环境搭建时间。 风险更高,需要 uptime、deep health、canary、rollback 和监控兜底。 暂时接受;staging 完整环境列为待确认。
PostHog / Admin 首版上线 更好观察 funnel 和人工排障。 不是打开 beta 的最低门槛,容易拉大 P0 范围。 推到 P1。

可复用方法

上线约束四问

在部署前问清:谁访问、从哪里访问、关页后怎样、最终产物是什么。

用户范围 → 地域入口 → 生命周期 → 产物标准

异步任务生产化检查

凡是超过几秒的 AI 任务,都要确认是否 durable、可恢复、可重试、可取消、可观测。

claim → lock → run_after → terminal state → restore

配置 bug 排查链

OAuth、域名、回调问题先不要改业务代码,先沿外部平台配置链路逐段验证。

症状 → URL 证据 → 平台配置 → 回调验证

P0/P1 截断法

P0 只保留“不能上线就会失败”的能力;P1 放提升运营效率但不阻塞 beta 的能力。

可部署 + 可恢复 + 可观测 + 可控成本

发布流程闭环

不要把 merge 当终点。生产发布要覆盖分支、CI、PR、release、deploy、health、monitor。

dev → main → release → deploy → uptime

边缘防护分层

Cloudflare 适合挡异常流量和缓存静态资源;业务成本控制必须回到服务端用户级配额。

WAF / cache / burst limit + per-user quota

工程证据

PR / Branch / Release

  • 流程:feature → devmain
  • PR:记录到 #29 由 dev 合并到 main
  • 当时部署 commit:3072c1e
  • Release:v0.1.1.2 一度落后于 main,需要补发新版 release
  • Checks:CI 曾失败,修复后继续;Production Uptime 后续通过

Deploy / Runtime

  • Render Web:storycam-web
  • Render Worker:storycam-worker
  • 区域:Singapore
  • Runtime:Native Runtime 暂用,ffmpeg 待真实 smoke 确认
  • 自定义域名:storycam.znbuild.com

Cloudflare / Uptime

  • DNS:Proxied
  • Static cache:Next.js static asset 检查命中 HIT
  • Dynamic bypass:/api/*/auth/*、authenticated paths
  • Rules:基础 WAF 和生成 endpoint burst limit
  • GitHub Uptime:public health、deep health、auth callback、static cache

Sentry / 安全

  • 独立项目:storycam/storycam
  • 不放在 geo-app
  • Issue alerts:新问题、回归、频率异常
  • 上下文脱敏:禁止 prompt、signed URL、provider body、secret
  • 所有密钥:[REDACTED]

文件 / 脚本

  • docs/DEPLOYMENT.md
  • docs/OBSERVABILITY.md
  • render.yaml
  • scripts/storycam-worker.ts
  • scripts/storycam-verify-live.mjs
  • DeepSeek / OpenRouter / Seedance smoke scripts

命令类别

pnpm storycam:verify:live
pnpm storycam:smoke:deepseek
pnpm storycam:smoke:openrouter
pnpm storycam:smoke:seedance
pnpm worker:storycam

命令作为工程证据列出;不包含任何 token、DSN 或 provider payload。

后续事项

已完成

  • 部署方案文档化。
  • P0 开发计划形成并实施。
  • Render Web / Worker 建立并随 main 部署。
  • Google OAuth、Supabase、Cloudflare 域名链路修复和验证。
  • Sentry 独立项目、issue alerts、GitHub uptime/deep health 配置。
  • Cloudflare cache/WAF/rate-limit 基础规则落地。

待确认

  • 真实生产 smoke:文本、图片、视频、ffmpeg final MP4。
  • 关页后 worker 继续生成,重新登录 restore 并下载真实 MP4。
  • Native Runtime ffmpeg 稳定性;必要时切 Docker。
  • 是否补齐完整 staging 环境。
  • Render dashboard 平台告警是否全部配置。
  • release/tag 与当前 main 部署状态对齐。

后续开发

  • PostHog safe events 和 funnel 分析。
  • 内部 /admin,查看 job / provider failure / 用户级状态。
  • 自动 post-deploy canary。
  • provider 成本和失败率 dashboard。
  • stuck job 手动 retry / cancel 工具。
  • 把已完成 observability plan 从 active 移到 completed,并同步部署文档状态。